/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.aljfce.business.event.boundary;

import com.aljfce.business.calendar.control.CalendarManager;
import com.aljfce.business.entity.Event;
import com.aljfce.business.entity.User;
import com.aljfce.business.event.control.EventManager;
import com.aljfce.business.event.control.EventWrapper;
import com.aljfce.business.forecast.exception.DayOutOfRangeException;
import com.aljfce.business.forecast.exception.ForecastNotFoundException;
import com.aljfce.business.profile.control.ProfileManager;
import com.aljfce.business.profile.exception.UserNotFoundException;
import com.aljfce.business.search.control.SearchManager;
import java.io.Serializable;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import org.primefaces.context.RequestContext;

import org.primefaces.event.SelectEvent;
import org.primefaces.model.DefaultScheduleEvent;
import org.primefaces.model.DefaultScheduleModel;
import org.primefaces.model.ScheduleEvent;
import org.primefaces.model.ScheduleModel;

/**
 *
 * @author EOroan
 *
 * This class boundary allows the interconnection between the View and the
 * Control during all kinds of modifications done by a user on his own events:
 * Creation, Deletion, Update.
 */
@ManagedBean
@ViewScoped
public class CreateEvent implements Serializable {

    @Inject
    private EventManager evm;
    @Inject
    private CalendarManager cm;
    @Inject
    private ProfileManager pm;

    @Inject
    private SearchManager sm;

    private ScheduleModel eventModel;

    private ScheduleModel lazyEventModel;

    private ScheduleEvent event;

    private Event selectedEvent;

    private User userSearched;

    /**
     * Get the value of userSearched
     *
     * @return the value of userSearched
     */
    public User getUserSearched() {
        return userSearched;
    }

    /**
     * Set the value of userSearched
     *
     * @param userSearched new value of userSearched
     */
    public void setUserSearched(User userSearched) {
        this.userSearched = userSearched;
    }

    private String userSearchedFound;

    /**
     * Get the value of userSearchedFound
     *
     * @return the value of userSearchedFound
     */
    public String getUserSearchedFound() {
        return userSearchedFound;
    }

    /**
     * Set the value of userSearchedFound
     *
     * @param userSearchedFound new value of userSearchedFound
     */
    public void setUserSearchedFound(String userSearchedFound) {
        this.userSearchedFound = userSearchedFound;
    }

    public Event getEventToCreate() {
        if (this.eventToCreate == null) {
            this.eventToCreate = new Event();
        }

        return eventToCreate;
    }

    public void setEventToCreate(Event eventToCreate) {
        this.eventToCreate = eventToCreate;
    }
    private Event eventToCreate;

    //List<Event> myEvents;
    private int index;

    /**
     * Get the value of index
     *
     * @return the value of index
     */
    public int getIndex() {
        return index;
    }

    /**
     * Set the value of index
     *
     * @param index new value of index
     */
    public void setIndex(int index) {
        this.index = index;
    }

    private String user_email;

    /**
     * Get the value of user_email
     *
     * @return the value of user_email
     */
    public String getUser_email() {
        return user_email;
    }

    /**
     * Set the value of user_email
     *
     * @param user_email new value of user_email
     */
    public void setUser_email(String user_email) {
        this.user_email = user_email;
    }

    private Boolean outdoor;

    /**
     * Get the value of outdoor
     *
     * @return the value of outdoor
     */
    public Boolean getOutdoor() {
        return outdoor;
    }

    /**
     * Set the value of outdoor
     *
     * @param outdoor new value of outdoor
     */
    public void setOutdoor(Boolean outdoor) {
        this.outdoor = outdoor;
    }

    private EventWrapper eventW = new EventWrapper();

    /**
     * Get the value of eventW
     *
     * @return the value of eventW
     */
    public EventWrapper getEventW() {
        return eventW;
    }

    /**
     * Set the value of eventW
     *
     * @param eventW new value of eventW
     */
    public void setEventW(EventWrapper eventW) {
        this.eventW = eventW;
    }

    private User user;

    /**
     * Get the value of user
     *
     * @return the value of user
     */
    public User getUser() {
        return user;
    }

    /**
     * Set the value of user
     *
     * @param user new value of user
     */
    public void setUser(User user) {
        this.user = user;
    }

    private ArrayList<User> usersToInvite;

    /**
     * Get the value of usersToInvite
     *
     * @return the value of usersToInvite
     */
    public ArrayList<User> getUsersToInvite() {
        return usersToInvite;
    }

    /**
     * Set the value of usersToInvite
     *
     * @param usersToInvite new value of usersToInvite
     */
    public void setUsersToInvite(ArrayList<User> usersToInvite) {
        this.usersToInvite = usersToInvite;
    }

    private ArrayList<Event> eventsOverlapping;

    /**
     * Get the value of eventsOverlapping
     *
     * @return the value of eventsOverlapping
     */
    public ArrayList<Event> getEventsOverlapping() {
        return eventsOverlapping;
    }

    /**
     * Set the value of eventsOverlapping
     *
     * @param eventsOverlapping new value of eventsOverlapping
     */
    public void setEventsOverlapping(ArrayList eventsOverlapping) {
        this.eventsOverlapping = eventsOverlapping;
    }

    private ArrayList o_EventsStrg;

    /**
     * Get the value of o_EventsStrg
     *
     * @return the value of o_EventsStrg
     */
    public ArrayList getO_EventsStrg() {
        return o_EventsStrg;
    }

    /**
     * Set the value of o_EventsStrg
     *
     * @param o_EventsStrg new value of o_EventsStrg
     */
    public void setO_EventsStrg(ArrayList o_EventsStrg) {
        this.o_EventsStrg = o_EventsStrg;
    }

    private boolean remove;

    /**
     * Get the value of remove
     *
     * @return the value of remove
     */
    public boolean isRemove() {
        return remove;
    }

    /**
     * Set the value of remove
     *
     * @param remove new value of remove
     */
    public void setRemove(boolean remove) {
        this.remove = remove;
    }

    private String userFound;

    /**
     * Get the value of userFound
     *
     * @return the value of userFound
     */
    public String getUserFound() {
        return userFound;
    }

    /**
     * Set the value of userFound
     *
     * @param userFound new value of userFound
     */
    public void setUserFound(String userFound) {
        this.userFound = userFound;
    }

    public CreateEvent() {
        this.principal = null/*request.getUserPrincipal()*/;
    }

    public void showCreateEvent() {
    }

    public Event getSelectedEvent() {
        return selectedEvent;
    }

    public void setSelectedEvent(Event selectedEvent) {
        this.selectedEvent = selectedEvent;
    }

    // Add business logic below. (Right-click in editor and choose
    FacesContext context = FacesContext.getCurrentInstance();
    HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();

    Principal principal/*request.getUserPrincipal()*/;

    @PostConstruct
    public void init() {

        this.event = new DefaultScheduleEvent();
        eventModel = new DefaultScheduleModel();
        this.user_email = "";
        this.outdoor = true;
        this.eventW = new EventWrapper();
        this.eventToCreate = new Event();
        this.eventsOverlapping = new ArrayList<>();
        this.usersToInvite = new ArrayList<>();
        this.remove = false;
        this.userFound = "";

        this.principal = this.request.getUserPrincipal();
//        this.showEvents(pm.getProfile(principal.getName()));

//        myEvents = new ArrayList<>();
        principal = request.getUserPrincipal();
        /*try {
         myEvents = udl.loadMyMonthlyCalendar(pm.getProfile(principal.getName()));
         } catch (IllegalArgumentException | CalendarNotFoundEception ex) {
         Logger.getLogger(ScheduleView.class.getName()).log(Level.SEVERE, null, ex);
         }*/

        /*lazyEventModel = new LazyScheduleModel() {

         @Override
         public void loadEvents(Date start, Date end) {
         Date random = getRandomDate(start); //take from entities
         addEvent(new DefaultScheduleEvent("Lazy Event 1", random, random));
                 
         random = getRandomDate(start);
         addEvent(new DefaultScheduleEvent("Lazy Event 2", random, random));
         }
         };*/
    }

    public Date getInitialDate() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(calendar.get(Calendar.YEAR), Calendar.FEBRUARY, calendar.get(Calendar.DATE), 0, 0, 0);

        return calendar.getTime();
    }

    public ScheduleModel getEventModel() {
        return eventModel;
    }
    /*    
     public ScheduleModel getLazyEventModel() {
     return lazyEventModel;
     }
     */

    private Calendar today() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DATE), 0, 0, 0);

        return calendar;
    }

    public void setIndoor() {
        eventToCreate.setOutdoor(false);
    }

    /**
     *
     * <b>checkEvent</b> handles the creation and the update of an event.
     *
     * @throws DayOutOfRangeException When the start date of the event to create
     * is far in the future and/or when the event is supposed to begin and/or
     * ends in the pass with respect to the actual date of its creation
     * @throws IllegalArgumentException The event to be created should not be
     * {@link null}
     * @throws ForecastNotFoundException When the weather forecast to associate
     * to the event to create is unavailable
     */
    public void checkEvent() throws DayOutOfRangeException, IllegalArgumentException, ForecastNotFoundException {

        try {
            eventsOverlapping = evm.controlEvent(pm.getProfile(principal.getName()), eventToCreate, usersToInvite);

            if (null == eventsOverlapping) {
                this.eventModel.addEvent(new EventWrapper(eventToCreate));
            } else {
                RequestContext contextOv = RequestContext.getCurrentInstance();
                contextOv.execute("PF('myoverlappings').show();");

            }
        } catch (UserNotFoundException ex) {
            Logger.getLogger(CreateEvent.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void showUserSearch(User user) {
        this.usersToInvite.add(user);
        if (user == null) {
            //call a JSF that use the following line
            userFound = "User not found!!";
        } else {
            //call a JSF that show the user_email
            userFound = user.getName();
        }
    }

    public void showOverlap() {
    }

    /**
     * <b>acceptOverlapping</b> allow to create or update an event even though
     * it's overlapping with other events in a calendar
     *
     * @param eventToCreate Event to create/update
     */
    public void acceptOverlap(Event eventToCreate) {
        //FIXME do something when this call fails
        try {
            User creator = pm.getProfile(principal.getName());
            if (eventToCreate.getId() != null) {
                evm.updateEvent(creator, eventToCreate, usersToInvite);
            } else {
                evm.createEvent(creator, eventToCreate, usersToInvite);
            }
            eventModel.addEvent(new EventWrapper(eventToCreate));

        } catch (UserNotFoundException ex) {
            Logger.getLogger(CreateEvent.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void editFromOverlap() {
    }

    public void addUser() {
        if (!usersToInvite.contains(user)) {
            usersToInvite.add(user);
        }
    }

    public void manageUser() {
        if (remove) {
            removeUser();
        } else {
            addUser();
        }
    }

    /**
     * Searches a {@link User} and saves the name associated to this user
     */
    public void submitUserSearch() {
        if (!principal.getName().equals(user_email)) {
            user = sm.findUser(user_email);
            if (user != null) {
                this.userFound = user.getName() + " " + user.getSurname();
            }
        }
    }

    public void backUserSearch() {
    }

    public void submitEventData() {
    }

    public void invite() {
    }

    /**
     * Remove a {@link User} from the set of users to invite to an {@link Event}
     */
    public void removeUser() {
        if (!usersToInvite.contains(user)) {
            usersToInvite.remove(user);
        }
        /*user_email = "";
         user = null;*/
    }

    /**
     *
     * @param user To remove from the set of users to invite to an {@link Event}
     */
    public void removeUser(User user) {
        this.usersToInvite.remove(user);
    }

    public void emptyUsersToInvite() {
        this.usersToInvite.clear();
    }

    public void back() {
    }

    public ScheduleEvent getEvent() {
        return event;
    }

    public void setEvent(ScheduleEvent event) {
        this.event = event;
    }

    /**
     * Adds to a JSF an {@link Object} representing an entity {@link Event}, in
     * order to visualize that event
     *
     * @param actionEvent
     */
    public void addEvent(ActionEvent actionEvent) {
        if (event.getId() == null) {
            eventModel.addEvent(event);
        } else {
            eventModel.updateEvent(event);
        }

        event = new DefaultScheduleEvent();
    }

    /*public void checkEvent(String title, User user, Date start, Date end, boolean outdoor, String location, String description) throws DayOutOfRangeException, IllegalArgumentException, ForecastNotFoundException {
     EventCreation.checkEvent(title, user, start, end, outdoor, location, description);
     }*/
    /**
     * Save in a boundary an event screened
     *
     * @param selectEvent Object took from a JSF representing the event screened
     */
    public void onEventSelect(SelectEvent selectEvent) {
        event = (ScheduleEvent) selectEvent.getObject();
        EventWrapper ew = (EventWrapper) selectEvent.getObject();
        selectedEvent = ew.getEvent();

    }

    /**
     * Allows to take a date from an retrieve to the screened calendar
     *
     * @param selectEvent Object took from a JSF
     */
    public void onDateSelect(SelectEvent selectEvent) {
        eventToCreate = new Event();
        eventToCreate.setStartingDate((Date) selectEvent.getObject());
        eventToCreate.setEndingTime((Date) selectEvent.getObject());

        event = new DefaultScheduleEvent("", (Date) selectEvent.getObject(), (Date) selectEvent.getObject());
    }

    private void addMessage(FacesMessage message) {
        FacesContext.getCurrentInstance().addMessage(null, message);
    }

}
